﻿// <copyright file="DecryptionExpert.cs" company="Microsoft Corporation">
// Copyright (c) 2009 All Right Reserved
// </copyright>
//
// <author>Netmon Cipher Dev Team</author>
// <date>2009-07-16</date>
// <version>1.0</version>
// <summary>This contains the form to read input arguments.</summary>

namespace NetmonDecryptionExpert
{
    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.IO;
    using System.Security.Principal;
    using System.Text;
    using System.Threading;
    using System.Windows.Forms;
    using System.Xml;
    using DecryptionExpertFramework;
    using Microsoft.NetworkMonitor.Automation;    

    /// <summary>
    /// Operation Status Enum
    /// </summary>
    public enum Status
    {
        /// <summary>
        /// Thread in Working State
        /// </summary>
        Working,

        /// <summary>
        /// The Decryption thread is complete
        /// </summary>
        Done
    }

    /// <summary>
    /// Class to take input arguments.
    /// </summary>
    public partial class DecryptionExpert : Form
    {
        #region Member Variables

        /// <summary>
        /// Time to sleep in milli seconds
        /// </summary>
        public const int SleepTime = 500;

        /// <summary>
        /// Stores maximum value of Progress Bar
        /// </summary>
        public const int MaxProgressBarValue = 100;

        /// <summary>
        /// Name of the config file
        /// </summary>
        private static StringBuilder configFileName;

        /// <summary>
        /// object to create config file
        /// </summary>
        private static XmlDocument document;

        /// <summary>
        /// Object of XmlNode to create Config node in config file
        /// </summary>
        private static XmlNode configNode;

        /// <summary>
        /// Object of XmlNode to create Protocols node in config file
        /// </summary>
        private static XmlNode protocolNode;

        /// <summary>
        /// Object of XmlNode to create Properties node in config file
        /// </summary>
        private static XmlNode propertyNode;

        /// <summary>
        /// Stores type of the certificate
        /// </summary>
        private static string certificateType = string.Empty;

        /// <summary>
        /// Name of the Conversation Filter
        /// </summary>
        private static string conversationFilter = string.Empty;

        /// <summary>
        /// Queue to hold the process name
        /// </summary>
        private static Queue<int> queue = new Queue<int>();

        /// <summary>
        /// Stores the status of operation.
        /// </summary>
        private Status status = Status.Working;

        /// <summary>
        /// UI Status Message.
        /// </summary>
        private string statusMessage = string.Empty;

        /// <summary>
        /// Stores message in case of error.
        /// </summary>
        private string decryptionResult = string.Empty;

        /// <summary>
        /// Stores the path of the DebugFile.
        /// </summary>
        private string debugFilePath = string.Empty;

        /// <summary>
        /// Used to spawn a separate thread for decryption
        /// </summary>
        private Thread thread = null;

        /// <summary>
        /// stores whether thread above is running
        /// </summary>
        private bool hasChildThreadStarted;

        /// <summary>
        /// Stores flag for running netmon.exe after processing the decryption
        /// </summary>
        private bool runNetmon;

        /// <summary>
        /// Stores flag for displaying any error messages to the user, turned off for automation
        /// </summary>
        private bool showErrors = true;

        /// <summary>
        /// Stores if there was an error encountered or not, only turned off if decryption was successful
        /// </summary>
        private bool isError = true;

        #endregion
        
        /// <summary>
        /// Initializes a new instance of the DecryptionExpert class.
        /// </summary>
        public DecryptionExpert()
        {
            this.InitializeComponent();
        }

        /// <summary>
        /// Initializes a new instance of the DecryptionExpert class.
        /// </summary>
        /// <param name="args">
        /// Arguments from Netmon UI
        /// </param>
        public DecryptionExpert(CommandLineArguments args)
        {
            this.InitializeComponent();
            this.expertProgressBar.Maximum = MaxProgressBarValue;
            this.expertProgressBar.Minimum = 0;

            // Show Password Field if Information is provided
            if (args.CertificatePassword != string.Empty || args.CertificatePath != string.Empty)
            {
                this.txtCertPassword.Visible = true;
            }
            
            this.txtEncCap.Text = args.CaptureFileName;
            conversationFilter = args.ConversationFilter;
            this.txtDecCap.Text = args.OutputPath;
            this.txtDebugPath.Text = args.LogPath;
            this.txtCertPath.Text = args.CertificatePath;
            this.txtCertPassword.Text = args.CertificatePassword;
            this.runNetmon = args.IsRunningNetmonAfter;
            this.showErrors = !args.IsSuppressingErrors;

            if (args.IsStartingNow)
            {
                this.Btn_Start_Click(null, null);
            }
        }

        /// <summary>
        /// Gets a value indicating whether an error has occurred
        /// </summary>
        public bool WasError
        {
            get { return this.isError; }
        }

        /// <summary>
        /// This method adds property node and its 
        /// attributes in config file
        /// </summary>
        /// <param name="propertyName">
        /// Name of the property
        /// </param>
        /// <param name="propertyValue">
        /// Value of the property
        /// </param>
        public static void AddPropertyNode(
                                string propertyName,
                                string propertyValue)
        {
            XmlNode xmlNode = document.CreateElement("Property");

            XmlAttribute nameAttribute = document.CreateAttribute("name");
            nameAttribute.Value = propertyName;

            XmlAttribute valueAttribute = document.CreateAttribute("value");
            valueAttribute.Value = propertyValue;

            xmlNode.Attributes.Append(nameAttribute);
            xmlNode.Attributes.Append(valueAttribute);
            propertyNode.AppendChild(xmlNode);
        }

        /// <summary>
        /// This method adds protocol node and its 
        /// attributes in config file
        /// </summary>
        /// <param name="protocolName">Name of the protocol</param>
        /// <param name="protocolValue">Value of the protocol</param>
        public static void AddProtocolNode(
                                string protocolName,
                                string protocolValue)
        {
            XmlNode xmlNode = document.CreateElement("Protocol");

            XmlAttribute nameAttribute = document.CreateAttribute("name");
            nameAttribute.Value = protocolName;

            XmlAttribute valueAttribute = document.CreateAttribute("value");
            valueAttribute.Value = protocolValue;

            xmlNode.Attributes.Append(nameAttribute);
            xmlNode.Attributes.Append(valueAttribute);
            protocolNode.AppendChild(xmlNode);
        }

        /// <summary>
        /// Open File Dialog Box to browse certificate
        /// </summary>
        /// <param name="sender">Sender Object</param>
        /// <param name="e">Event Arguments</param>
        private void Btn_BrowseCert_Click(object sender, EventArgs e)
        {
            this.openCertificateFile.InitialDirectory = Utils.GetDirectory(this.txtEncCap.Text);
            this.openCertificateFile.Filter = "Key files(*.key)|*.key|"
                + "PEM files(*.pem)|*.pem|"
                + "Pfx files(*.pfx)|*.pfx|"
                + "All files(*.*)|*.*";

            this.openCertificateFile.FilterIndex = 3;
            this.openCertificateFile.RestoreDirectory = true;
            const int FileExtLength = 4;
            if (this.openCertificateFile.ShowDialog() == DialogResult.OK)
            {
                this.txtCertPath.Text = this.openCertificateFile.FileName;

                certificateType = this.txtCertPath.Text.Substring(
                    this.txtCertPath.Text.Length - FileExtLength, FileExtLength).ToLower();

                this.CheckCertificateExtension(certificateType);
            }
        }

        /// <summary>
        /// Save As File Dialog Box to get Decrypted File Path.
        /// </summary>
        /// <param name="sender">Sender Object</param>
        /// <param name="e">Event Arguments</param>
        private void Btn_DecPath_Click(object sender, EventArgs e)
        {
            this.saveFile.Reset();
            this.saveFile.Filter = "cap files (*.cap)|*.cap";
            this.saveFile.InitialDirectory = Utils.GetDirectory(this.txtEncCap.Text);
            this.saveFile.RestoreDirectory = true;
            this.saveFile.DefaultExt = ".cap";

            if (this.saveFile.ShowDialog() == DialogResult.OK)
            {
                this.txtDecCap.Text = this.saveFile.FileName;
                this.CheckCaptureFileExtension(
                    this.txtDecCap.Text.Substring(this.txtDecCap.Text.Length - 4, 4).ToLower());
            }
        }

        /// <summary>
        /// Open File Dialog Box to browse Debug File Path
        /// </summary>
        /// <param name="sender">Sender Object</param>
        /// <param name="e">Event Arguments</param>
        private void Btn_DebugPath_Click(object sender, EventArgs e)
        {
            this.saveFile.Reset();
            this.saveFile.Filter = @"Txt files (*.txt)|*.txt|Dat files (*.dat)|*.dat
                                    |Log files (*.log)|*.log|All files (*.*)|*.*";

            if (string.IsNullOrEmpty(this.txtDecCap.Text))
            {
                this.saveFile.InitialDirectory = Utils.GetDirectory(this.txtEncCap.Text);
            }
            else
            {
                this.saveFile.InitialDirectory = Utils.GetDirectory(this.txtDecCap.Text);
            }

            this.saveFile.RestoreDirectory = true;
            this.saveFile.DefaultExt = ".txt";

            if (this.saveFile.ShowDialog() == DialogResult.OK)
            {
                this.txtDebugPath.Text = this.saveFile.FileName;
                this.CheckDebugFileExtension(
                    this.txtDebugPath.Text.Substring(this.txtDebugPath.Text.Length - 4, 4).ToLower());
            }
        }

        /// <summary>
        /// Checks Entension of Decrypted Capture File
        /// and Debug File.
        /// </summary>
        /// <returns>Returns TRUE if correct.</returns>
        private bool CheckFileExtenions()
        {
            if (this.CheckCaptureFileExtension(
                    this.txtDecCap.Text.Substring(this.txtDecCap.Text.Length - 4, 4).ToLower()))
            {
                if (!string.IsNullOrEmpty(this.txtDebugPath.Text))
                {
                    if (this.CheckDebugFileExtension(
                            this.txtDebugPath.Text.Substring(this.txtDebugPath.Text.Length - 4, 4).ToLower()))
                    {
                        return true;
                    }
                }
                else
                {
                    return true;
                }
            }

            return false;
        }

        /// <summary>
        /// Checks Capture File Extension.
        /// </summary>
        /// <param name="captureFileName">Name of Capture File.</param>
        /// <returns>Returns TRUE if correct.</returns>
        private bool CheckCaptureFileExtension(string captureFileName)
        {
            if (!captureFileName.Equals(".cap"))
            {
                if (this.showErrors)
                {
                    MessageBox.Show(
                       "Extension of the Decrypted capture file is not a valid" +
                       "\nPlease add .cap as an extension",
                       "Invalid File Extension",
                       MessageBoxButtons.OK,
                       MessageBoxIcon.Error);
                }

                this.txtDecCap.Text = string.Empty;
                this.txtDecCap.Focus();

                return false;
            }

            return true;
        }

        /// <summary>
        /// Checks the Extension of the Certificate File
        /// </summary>
        /// <param name="fileExtension">File Extension to be checked.</param>
        /// <returns>Returns TRUE is Supported Certificate Type.</returns>
        private bool CheckCertificateExtension(string fileExtension)
        {
            this.lblCertPassword.Visible = false;
            this.txtCertPassword.Visible = false;

            if (!fileExtension.Equals(".pem"))
            {
                if (!fileExtension.Equals(".key"))
                {
                    if (!fileExtension.Equals(".pfx"))
                    {
                        if (this.showErrors)
                        {
                            MessageBox.Show(
                                "This type of certificate is not supported by this expert"
                                + "\nOnly PEM and PFX certificates are supported.",
                                "Invalid Certificate type",
                                MessageBoxButtons.OK,
                                MessageBoxIcon.Error);
                        }

                        return false;
                    }
                    else
                    {
                        this.lblCertPassword.Visible = true;
                        this.txtCertPassword.Visible = true;
                    }
                }
            }

            return true;
        }

        /// <summary>
        /// This method validates the extension of file
        /// </summary>
        /// <param name="fileExtension">Extension of the file</param>
        /// <returns>True if the extension is valid otherwise false</returns>
        private bool CheckDebugFileExtension(string fileExtension)
        {
            if (!fileExtension.Equals(".txt"))
            {
                if (!fileExtension.Equals(".dat"))
                {
                    if (!fileExtension.Equals(".log"))
                    {
                        if (this.showErrors)
                        {
                            MessageBox.Show(
                            "This is not a valid file extension.",
                            "Invalid extension",
                            MessageBoxButtons.OK,
                            MessageBoxIcon.Error);
                        }

                        this.txtDebugPath.Text = string.Empty;
                        this.txtDebugPath.Focus();

                        return false;
                    }
                }
            }

            return true;
        }

        /// <summary>
        /// This method checks if any field 
        /// entered by user is null
        /// </summary>
        /// <returns>
        /// True, if any of the field is not entered 
        /// and prompts an error message to enter
        /// otherwise False
        /// </returns>
        private bool IsAnyFieldNull()
        {
            if (string.IsNullOrEmpty(this.txtCertPath.Text))
            {
                if (this.showErrors)
                {
                    MessageBox.Show(
                        "Please enter Server Certificate Path",
                        "Invalid Server Certificate",
                        MessageBoxButtons.OK,
                        MessageBoxIcon.Error);
                }

                this.txtCertPath.Focus();
                return true;
            }

            if (string.IsNullOrEmpty(this.txtCertPassword.Text) && certificateType.Equals(".pfx"))
            {
                if (this.showErrors)
                {
                    MessageBox.Show(
                        "Server Certificate Password cannot be null",
                        "Null Password",
                        MessageBoxButtons.OK,
                        MessageBoxIcon.Error);
                }

                this.txtCertPassword.Focus();
                return true;
            }

            if (string.IsNullOrEmpty(this.txtDecCap.Text))
            {
                if (this.showErrors)
                {
                    MessageBox.Show(
                        "Decrypted File Path cannot be null",
                        "Invalid capture file name",
                        MessageBoxButtons.OK,
                        MessageBoxIcon.Error);
                }

                this.txtDecCap.Focus();
                return true;
            }         

            return false;
        }

        /// <summary>
        /// Method to check if process is running
        /// </summary>
        /// <param name="processName">Process name</param>
        /// <param name="decapFilename">Decryptedfile Name</param>
        /// <returns>true if opened</returns>
        private bool CheckProcessExistanceByName(
                                string processName,
                                string decapFilename)
        {
            bool ret = false;
            try
            {
                Process[] p = Process.GetProcessesByName(processName);

                if (p.Length == 0)
                {
                    return false;
                }

                for (int i = 0; i < p.Length; i++)
                {
                    if (!queue.Contains(p[i].Id))
                    {
                        if (p[i].MainWindowTitle.EndsWith(decapFilename))
                        {
                            return true;
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                if (this.showErrors)
                {
                    MessageBox.Show(ex.Message, "Error");
                }

                ret = false;
            }

            return ret;
        }

        /// <summary>
        /// Creates a Config file and writes the 
        /// information entered by user
        /// </summary>
        private void CreateConfigFile()
        {
            try
            {
                configFileName = new StringBuilder("defConfig.xml");
                document = new XmlDocument();
                XmlNode xmlNode = document.CreateXmlDeclaration("1.0", "UTF-8", null);
                document.AppendChild(xmlNode);
                configNode = document.CreateElement("config");
                protocolNode = document.CreateElement("Protocols");
                propertyNode = document.CreateElement("Properties");
                this.AddChildNodes();
                configNode.AppendChild(protocolNode);
                configNode.AppendChild(propertyNode);
                document.AppendChild(configNode);
                string tempPath = Path.GetTempPath();
                configFileName.Insert(0, tempPath);
                document.Save(configFileName.ToString());
            }
            catch (Exception ex)
            {
                if (this.showErrors)
                {
                    MessageBox.Show(ex.Message);
                }
            }
        }

        /// <summary>
        /// This method adds child nodes to Config node 
        /// in config file.
        /// </summary>
        private void AddChildNodes()
        {
            AddProtocolNode("SSL", true.ToString());

            AddPropertyNode("EncryptedCaptureFile", this.txtEncCap.Text);

            AddPropertyNode("DecryptedCaptureFile", this.txtDecCap.Text);

            AddPropertyNode("Certificate", this.txtCertPath.Text);

            AddPropertyNode("CertificatePassword", this.txtCertPassword.Text);

            AddPropertyNode("DebugLog", this.debugFilePath);

            AddPropertyNode("ConversationFilter", conversationFilter);
        }
        
        /// <summary>
        /// Calls the Common Framework Library
        /// to Decrypt the capture file.
        /// </summary>
        /// <param name="obj">Object of DecryptNetmonCapture class</param>
        private void Decrypt(object obj)
        {
            DecryptNetmonCapture objDecryption = (DecryptNetmonCapture)obj;

            bool res = objDecryption.DecryptCapture(
                                            configFileName.ToString(),
                                            out this.decryptionResult);

            this.hasChildThreadStarted = false;

            this.status = Status.Done;
        }
       
        /// <summary>
        /// Form Close Event Handler
        /// </summary>
        /// <param name="sender">Sender Object</param>
        /// <param name="e">Form Closing Event Arguments</param>
        private void DecryptionExpert_FormClosing(object sender, FormClosingEventArgs e)
        {            
            if (this.hasChildThreadStarted)
            {
                e.Cancel = true;
            }     
        }

        /// <summary>
        /// Start Button Event Handler
        /// </summary>
        /// <param name="sender">Sender Object</param>
        /// <param name="e">Event Arguments</param>
        private void Btn_Start_Click(object sender, EventArgs e)
        {
            this.expertProgressBar.Value = 0;
            this.btnStart.Enabled = false;
            this.btnBrowseCert.Enabled = false;
            this.btnDebugPath.Enabled = false;
            this.btnDecPath.Enabled = false;
            this.txtDecCap.Enabled = false;

            if (!this.Btn_Start_Work())
            {
                // Note: Also update this in the finishing code
                this.btnStart.Enabled = true;
                this.btnBrowseCert.Enabled = true;
                this.btnDebugPath.Enabled = true;
                this.btnDecPath.Enabled = true;
                this.txtDecCap.Enabled = true;
            }
        }

        /// <summary>
        /// Called by the Start Button to encapsulate input validation
        /// </summary>
        /// <returns>false if there is an input error</returns>
        private bool Btn_Start_Work()
        {
            const int MinFileNameLength = 5;
            if (this.IsAnyFieldNull())
            {
                return false;
            }

            if (this.txtDecCap.Text.Length < MinFileNameLength)
            {
                if (this.showErrors)
                {
                    MessageBox.Show("Cannot create Decrypted file, Please enter a Proper File Name");
                }

                return false;
            }

            if (!string.IsNullOrEmpty(this.txtDebugPath.Text))
            {
                if (this.txtDebugPath.Text.Length < MinFileNameLength)
                {
                    if (this.showErrors)
                    {
                        MessageBox.Show("Cannot create Debug file, Please enter a Proper File Name");
                    }

                    return false;
                }

                if (!Utils.CreateDirectoryIfNotExists(this.txtDebugPath.Text))
                {
                    if (this.showErrors)
                    {
                        MessageBox.Show(
                        "Specified Directory does not exist",
                        this.txtDebugPath.Text,
                        MessageBoxButtons.OK,
                        MessageBoxIcon.Error);
                    }

                    this.txtDebugPath.Text = string.Empty;
                    this.txtDebugPath.Focus();
                    return false;
                }

                this.debugFilePath = this.txtDebugPath.Text;
            }
            else
            {
                this.debugFilePath = Path.GetTempPath() + "Debug.txt";
            }

            if (!this.CheckFileExtenions())
            {
                if (this.showErrors)
                {
                    MessageBox.Show("File Format Not Recognized, please check extensions.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }

                return false;
            }

            if (this.CheckProcessExistanceByName("netmon", this.txtDecCap.Text))
            {
                if (this.showErrors)
                {
                    MessageBox.Show(
                            this.txtDecCap.Text +
                            " cannot replace the existing" +
                            " file since it is already in use",
                            this.txtDecCap.Text,
                            MessageBoxButtons.OK,
                            MessageBoxIcon.Error);
                }

                return false;
            }

            if (Utils.CreateDirectoryIfNotExists(this.txtDecCap.Text))
            {
                //// Checks whether a file can be created at given path
                this.txtDecCap.Text = Utils.CheckFileCreation(this.txtDecCap.Text);
                this.debugFilePath = Utils.CheckFileCreation(this.debugFilePath);
                this.txtDecCap.Refresh();

                //// Creates a config file
                this.CreateConfigFile();

                this.lblProcess.Visible = true;
                this.expertProgressBar.Visible = true;

                string decryptionResult = string.Empty;

                this.status = Status.Working;

                /*WaitCallback doWork = new WaitCallback(this.DecryptCaptureFile);
                ThreadPool.QueueUserWorkItem(doWork);                */
                if (!backgroundWorker.IsBusy)
                {
                    backgroundWorker.RunWorkerAsync();
                }
            }
            else
            {
                if (this.showErrors)
                {
                    MessageBox.Show(
                    "Specified Directory does not exist",
                    this.txtDecCap.Text,
                    MessageBoxButtons.OK,
                    MessageBoxIcon.Error);
                }

                this.txtDecCap.Text = string.Empty;
                this.txtDecCap.Focus();
                return false;
            }

            return true;
        }

        /// <summary>
        /// Used to encapsulate decryption threading to isolate UI
        /// </summary>
        /// <param name="sender">Sender Object</param>
        /// <param name="e">Event Arguments</param>
        private void BackgroundWorker_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
        {
            DecryptNetmonCapture objDecryption = new DecryptNetmonCapture();

            //// Subscribe the function
            // TODO: rework decryption infrastructure to use better threading model for logging
            objDecryption.Log += new DecryptNetmonCapture.LogEventHandler(this._updateNotice);

            ParameterizedThreadStart updateInfo =
                new ParameterizedThreadStart(this.Decrypt);
            this.thread = new Thread(updateInfo);
            this.hasChildThreadStarted = true;
            this.thread.Start(objDecryption);

            while (this.status == Status.Working)
            {
                Thread.Sleep(SleepTime);
                objDecryption.UpdateProgressBar();
                ////backgroundWorker.ReportProgress(10, "");
            }

            e.Result = objDecryption;
        }

        /// <summary>
        /// Used to encapsulate callbacks from the decryption engine to buffer the UI from threading violations.
        /// </summary>
        /// <param name="message">Progress string update for current operation</param>
        private void _updateNotice(string message)
        {
            backgroundWorker.ReportProgress(10, message);
        }

        /// <summary>
        /// Called to update the progress of the UI from the thread
        /// </summary>
        /// <param name="sender">Sender Object</param>
        /// <param name="e">Event Arguments</param>
        private void BackgroundWorker_ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e)
        {
            string message = (string)e.UserState;

            if (this.expertProgressBar.Value == MaxProgressBarValue)
            {
                this.expertProgressBar.Value = 0;
            }

            if (message != this.statusMessage)
            {
                this.statusMessage = message;
                this.lblProcess.Text = message;
                this.lblProcess.Refresh();
                this.expertProgressBar.Increment(e.ProgressPercentage);
                this.expertProgressBar.Refresh();
            }
        }

        /// <summary>
        /// Called when decryption is completed.  Will display errors to the user if decryption was unsuccessful or run netmon.exe
        /// </summary>
        /// <param name="sender">Sender Object</param>
        /// <param name="e">Event Arguments</param>
        private void BackgroundWorker_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
        {
            DecryptNetmonCapture objDecryption = e.Result as DecryptNetmonCapture;

            if (objDecryption.IncorrectCertificate)
            {
                if (this.showErrors &&
                    MessageBox.Show(
                                       "Invalid Key Exchange data or Invalid Certificate"
                                       + "\n Do you want to re-try?",
                                       "Decryption Expert: Message",
                                       MessageBoxButtons.YesNo,
                                       MessageBoxIcon.Question) == DialogResult.Yes)
                {
                    this.txtCertPath.Text = string.Empty;
                    this.txtCertPath.Focus();
                    this.txtCertPath.Refresh();
                    this.txtCertPassword.Text = string.Empty;
                    this.txtCertPassword.Visible = false;
                    this.lblCertPassword.Visible = false;
                    this.lblProcess.Visible = false;
                    this.expertProgressBar.Visible = false;
                }
                else
                {
                    this.Close();
                }
            }
            else if (objDecryption.PasswordMismatch)
            {
                if (this.showErrors && MessageBox.Show(
                                "Specified password is not correct or there was a problem accessing the Private Key."
                                + "\n Do you want to re-try?",
                                "Decryption Expert: Message",
                                MessageBoxButtons.YesNo,
                                MessageBoxIcon.Question) == DialogResult.Yes)
                {
                    this.txtCertPassword.Text = string.Empty;
                    this.txtCertPassword.Focus();
                    this.txtCertPassword.Refresh();
                    this.lblProcess.Visible = false;
                    this.expertProgressBar.Visible = false;
                }
                else
                {
                    this.Close();
                }
            }
            else if (!objDecryption.DecryptionSuccessful)
            {
                if (this.showErrors)
                {
                    if (objDecryption.ErrorText != null)
                    {
                        MessageBox.Show(
                        objDecryption.ErrorText,
                        "Decryption Expert: Error",
                        MessageBoxButtons.OK,
                        MessageBoxIcon.Error);
                    }
                    else
                    {
                        MessageBox.Show(
                        "Unspecified Error",
                        "Decryption Expert: Error",
                        MessageBoxButtons.OK,
                        MessageBoxIcon.Error);
                    }
                }
                else
                {
                    // Close on bad errors
                    this.Close();
                }

                this.expertProgressBar.Visible = false;
            }
            else
            {
                // Success!
                this.lblProcess.Text = "Process Completed.";
                this.lblProcess.Refresh();
                this.expertProgressBar.Increment(MaxProgressBarValue - this.expertProgressBar.Value);
                this.expertProgressBar.Refresh();

                // Launch Netmon
                if (this.runNetmon)
                {
                    System.Diagnostics.Process openCap = new System.Diagnostics.Process();
                    openCap.StartInfo.FileName = "netmon.exe";
                    openCap.StartInfo.Arguments = this.txtDecCap.Text;
                    openCap.Start();
                }

                // Only successful path to exit Expert.
                this.isError = false;

                this.Close();
            }

            this.btnStart.Enabled = true;
            this.btnBrowseCert.Enabled = true;
            this.btnDebugPath.Enabled = true;
            this.btnDecPath.Enabled = true;
            this.txtDecCap.Enabled = true;
        }
    }
}